package com.lechi.web.controller;

import com.lechi.iot.android.entity.OutDeviceCmd;
import com.lechi.web.common.annotation.Anonymous;
import com.lechi.web.common.annotation.Log;
import com.lechi.web.common.annotation.RepeatSubmit;
import com.lechi.web.common.config.LeChiConfig;
import com.lechi.web.common.core.controller.BaseController;
import com.lechi.web.common.core.domain.AjaxResult;
import com.lechi.web.common.core.page.TableDataInfo;
import com.lechi.web.common.enums.BusinessType;
import com.lechi.web.common.exception.ExceptionUtil;
import com.lechi.web.common.utils.SecurityUtils;
import com.lechi.web.common.utils.file.FileUploadUtils;
import com.lechi.web.common.utils.file.FileUtils;
import com.lechi.web.constants.AppCmdConstants;
import com.lechi.web.constants.Constants;
import com.lechi.web.framework.util.GuavaCacheUtil;
import com.lechi.web.service.IIotAndroidDeviceService;
import com.lechi.web.service.IIotDeviceService;
import com.lechi.web.service.IIotOnlineLogService;
import com.lechi.web.service.IIotSourceFileService;
import com.lechi.web.system.domain.IotAndroidDeviceBo;
import com.lechi.web.system.domain.IotDeviceBo;
import com.lechi.web.system.domain.IotOnlineLog;
import com.lechi.web.system.domain.IotSourceFile;
import com.lechi.web.util.LeChiCacheUtil;
import com.lechi.web.vo.*;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * 设备 default Controller
 *
 * @author yangguang
 * @date 2024 -03-20
 */
@Slf4j
@RestController
@RequestMapping("/iot/app/device")
@RequiredArgsConstructor
public class IotAndroidDeviceController extends BaseController {

    private final IIotDeviceService deviceService;

    private final LeChiConfig leChiConfig;

    private final IIotSourceFileService iotSourceFileService;

    private final IIotAndroidDeviceService androidDeviceService;

    private final IIotOnlineLogService iotOnlineLogService;


    /**
     * Reload ajax result.
     *
     * @param iotDeviceAppCmdVo the iot device app cmd vo
     * @return the ajax result
     */
    @PostMapping("/reload")
    //    @PreAuthorize("@ss.hasPermi('iot:app:reload')")
    public AjaxResult reload(@RequestBody @Valid IotDeviceAppCmdVo iotDeviceAppCmdVo) {
        final String deviceSN = iotDeviceAppCmdVo.getDeviceSN();
        OutDeviceCmd outDeviceCmd = new OutDeviceCmd();
        outDeviceCmd.setDeviceSN(deviceSN);
        outDeviceCmd.setCmd(AppCmdConstants.RELOAD_COMMAND);
        deviceService.sendCmdToApp(deviceSN, outDeviceCmd);
        return AjaxResult.success();
    }

    /**
     * Screen ajax result.
     *
     * @param iotDeviceAppCmdVo the iot device app cmd vo
     * @return the ajax result
     */
    @PostMapping("/screen")
    @Log(title = "截屏操作", businessType = BusinessType.UPDATE)
    //    @PreAuthorize("@ss.hasPermi('iot:app:screen')")
    public AjaxResult screen(@RequestBody @Valid IotDeviceAppCmdVo iotDeviceAppCmdVo) {
        final String deviceSN = iotDeviceAppCmdVo.getDeviceSN();
        OutDeviceCmd outDeviceCmd = new OutDeviceCmd();
        outDeviceCmd.setDeviceSN(deviceSN);
        outDeviceCmd.setCmd(AppCmdConstants.SCREEN_SHOT);
        deviceService.sendCmdToApp(deviceSN, outDeviceCmd);
        return AjaxResult.success();
    }

    /**
     * Power on off ajax result.
     *
     * @param iotDevicePowerOnOffVo the iot device power on off vo
     * @return the ajax result
     */
    @RepeatSubmit
    @PostMapping("/powerOnOff")
    @Log(title = "开关机操作", businessType = BusinessType.UPDATE)
    //    @PreAuthorize("@ss.hasPermi('iot:app:powerOnOff')")
    public AjaxResult powerOnOff(@RequestBody @Valid IotDevicePowerOnOffVo iotDevicePowerOnOffVo) {
        final String deviceSN = iotDevicePowerOnOffVo.getDeviceSN();
        OutDeviceCmd outDeviceCmd = new OutDeviceCmd();
        outDeviceCmd.setDeviceSN(deviceSN);
        outDeviceCmd.setCmd(AppCmdConstants.POWER_ON_OFF);
        outDeviceCmd.setTimes(iotDevicePowerOnOffVo.getTimes());
        deviceService.sendCmdToApp(deviceSN, outDeviceCmd);
        return AjaxResult.success();
    }

    @RepeatSubmit
    @PostMapping("/screenOnOff")
    @Log(title = "息屏操作", businessType = BusinessType.UPDATE)
    //    @PreAuthorize("@ss.hasPermi('iot:app:powerOnOff')")
    public AjaxResult screenOnOff(@RequestBody @Valid IotDevicePowerOnOffVo iotDevicePowerOnOffVo) {
        final String deviceSN = iotDevicePowerOnOffVo.getDeviceSN();
        OutDeviceCmd outDeviceCmd = new OutDeviceCmd();
        outDeviceCmd.setDeviceSN(deviceSN);
        outDeviceCmd.setCmd(AppCmdConstants.SCREEN_ON_OFF);
        outDeviceCmd.setPublishContent(iotDevicePowerOnOffVo.getScreenOnOff());
        deviceService.sendCmdToApp(deviceSN, outDeviceCmd);
        return AjaxResult.success();
    }

    /**
     * Notify ajax result.
     *
     * @param iotDeviceAppCmdVo the iot device app cmd vo
     * @return the ajax result
     */
    @RepeatSubmit
    @PostMapping("/notify")
    //    @PreAuthorize("@ss.hasPermi('iot:app:notify')")
    public AjaxResult notify(@RequestBody @Valid IotDeviceAppCmdVo iotDeviceAppCmdVo) {
        final String deviceSN = iotDeviceAppCmdVo.getDeviceSN();
        OutDeviceCmd outDeviceCmd = new OutDeviceCmd();
        outDeviceCmd.setDeviceSN(deviceSN);
        outDeviceCmd.setCmd(iotDeviceAppCmdVo.getCmd());
        if ("rotation".equalsIgnoreCase(iotDeviceAppCmdVo.getCmd())) {
            outDeviceCmd.setRotation(iotDeviceAppCmdVo.getRotation());
        }
        deviceService.sendCmdToApp(deviceSN, outDeviceCmd);
        return AjaxResult.success();
    }


    /**
     * 查询设备 default 列表
     *
     * @param iotDeviceQueryVo the iot device query vo
     * @return the table data info
     */
    @GetMapping("/list")
    //    @PreAuthorize("@ss.hasPermi('iot:app:query')")
    public TableDataInfo list(IotDeviceQueryVo iotDeviceQueryVo) {
        startPage();
        IotDeviceBo iotDeviceBo = new IotDeviceBo();
        BeanUtils.copyProperties(iotDeviceQueryVo, iotDeviceBo);
        iotDeviceBo.setProtocolType(String.format("'%s'", Constants.ANDROID_TCP));
        List<IotDeviceBo> list = deviceService.selectIotDeviceList(iotDeviceBo);
        list.forEach(androidDevice -> androidDevice.setStatus(LeChiCacheUtil.ifTimeOut(androidDevice.getDeviceSn(), androidDevice.getTimeInterval())));
        return getDataTable(list);
    }

    /**
     * 获取设备 default 详细信息
     *
     * @param id the id
     * @return the info
     */
    @GetMapping(value = "/{id}")
    //    @PreAuthorize("@ss.hasPermi('iot:app:query')")
    public AjaxResult getInfo(@PathVariable("id") Long id) {
        IotDeviceBo iotDeviceBo = Optional.ofNullable(deviceService.selectIotDeviceById(id)).orElseThrow(ExceptionUtil.notExitsErrorException);
        IotAndroidDeviceVo iotDeviceResult = new IotAndroidDeviceVo();
        BeanUtils.copyProperties(iotDeviceBo, iotDeviceResult);
        return success(iotDeviceResult);
    }

    /**
     * 获取android设备配置信息
     *
     * @param deviceSN the device sn
     * @return the android info
     */
    @RepeatSubmit
    @GetMapping(value = "/android/{deviceSN}")
    //    @PreAuthorize("@ss.hasPermi('iot:app:query')")
    public AjaxResult getAndroidInfo(@PathVariable("deviceSN") String deviceSN) {
        IotAndroidDeviceBo androidDeviceBo = new IotAndroidDeviceBo();
        androidDeviceBo.setDeviceSN(deviceSN);
        IotAndroidDeviceBo iotDeviceBo = androidDeviceService.selectIotAndroidDevice(androidDeviceBo);
        return success(iotDeviceBo);
    }

    /**
     * 查询android在线日志记录列表
     *
     * @param iotUpgradeLogVo the iot upgrade log vo
     * @return the table data info
     */
    @RepeatSubmit
    @GetMapping("/online")
    //    @PreAuthorize("@ss.hasPermi('iot:app:query')")
    public TableDataInfo online(IotOnlineLogVo iotUpgradeLogVo) {
        startPage();
        IotOnlineLog iotOnlineLog = new IotOnlineLog();
        iotOnlineLog.setDeviceSN(iotUpgradeLogVo.getDeviceSN());
        List<IotOnlineLog> list = iotOnlineLogService.selectIotOnlineLogList(iotOnlineLog);
        return getDataTable(list);
    }

    /**
     * 新增设备 default
     *
     * @param iotDeviceVo the iot device vo
     * @return the ajax result
     */
    @RepeatSubmit
    @PostMapping("/add")
    @Log(title = "新增设备操作", businessType = BusinessType.INSERT)
    @Transactional(rollbackFor = Exception.class)
    //    @PreAuthorize("@ss.hasPermi('iot:app:add')")
    public AjaxResult add(@RequestBody @Valid IotAndroidDeviceVo iotDeviceVo) {
        IotDeviceBo iotDeviceBo = new IotDeviceBo();
        BeanUtils.copyProperties(iotDeviceVo, iotDeviceBo);
        // 获取当前的用户名称
        String username = SecurityUtils.getUsername();
        iotDeviceBo.setCreateBy(username);

        iotDeviceBo.setTimeInterval(1);
        deviceService.insertIotDevice(iotDeviceBo);

        IotAndroidDeviceBo iotAndroidDeviceBo = new IotAndroidDeviceBo();
        iotAndroidDeviceBo.setDeviceSN(iotDeviceVo.getDeviceSn());
        androidDeviceService.insertIotAndroidDevice(iotAndroidDeviceBo);
        String androidDeviceSn = iotDeviceVo.getDeviceSn();
        GuavaCacheUtil.getBiDeviceSnAndIPMap().putIfAbsent(androidDeviceSn, androidDeviceSn);
        return success();
    }

    /**
     * 修改设备 default
     *
     * @param iotDeviceVo the iot device vo
     * @return the ajax result
     */
    @PostMapping("/edit")
    @Log(title = "编辑设备操作", businessType = BusinessType.UPDATE)
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.SERIALIZABLE)
    //    @PreAuthorize("@ss.hasPermi('iot:app:edit')")
    public AjaxResult edit(@RequestBody @Valid IotAndroidDeviceVo iotDeviceVo) {
        IotDeviceBo iotDeviceBo = new IotDeviceBo();
        String username = SecurityUtils.getUsername();
        iotDeviceBo.setUpdateBy(username);
        BeanUtils.copyProperties(iotDeviceVo, iotDeviceBo);
        IotDeviceBo oldIotDeviceBo = deviceService.selectIotDeviceById(iotDeviceVo.getId());
        String androidDeviceSn = iotDeviceVo.getDeviceSn();
        deviceService.updateIotDevice(iotDeviceBo);
        if (oldIotDeviceBo.getDeviceSn().equals(androidDeviceSn)) { // 新旧序列号一致，不需要重新建表，缓冲等操作
            return AjaxResult.success();
        }
        IotAndroidDeviceBo iotAndroidDeviceBo = new IotAndroidDeviceBo();
        iotAndroidDeviceBo.setDeviceSN(iotDeviceVo.getDeviceSn());
        androidDeviceService.insertIotAndroidDevice(iotAndroidDeviceBo);

//        GuavaCacheUtil.getBiDeviceSnAndIPMap().remove(oldIotDeviceBo.getDeviceSn());
        GuavaCacheUtil.getBiDeviceSnAndIPMap().putIfAbsent(androidDeviceSn, androidDeviceSn);
        return AjaxResult.success();
    }

    /**
     * 删除设备 default
     *
     * @param ids the ids
     * @return the ajax result
     */
    @DeleteMapping("/{ids}")
    @Log(title = "删除设备操作", businessType = BusinessType.DELETE)
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
    //    @PreAuthorize("@ss.hasPermi('iot:app:remove')")
    public AjaxResult remove(@PathVariable Long[] ids) {
        deviceService.deleteIotDeviceByIds(ids);
        return AjaxResult.success();
    }

    /**
     * 上传快照文件
     *
     * @param deviceSN the device sn
     * @param file     the file
     * @return the ajax result
     */
    @Anonymous
    @PostMapping(value = "/upload", consumes = "multipart/form-data")
    //    @PreAuthorize("@ss.hasPermi('iot:app:upload')")
    public AjaxResult uploadFile(@RequestParam("deviceSN") String deviceSN, @RequestParam("file") MultipartFile file) {
        try {
            String filePath = LeChiConfig.getScreenshotUploadPath();
            String fileName = FileUploadUtils.uploadImage(filePath, file);
            String url = leChiConfig.getNginxip() + fileName;
            IotSourceFile iotSourceFile = new IotSourceFile();
            iotSourceFile.setSourceName(deviceSN);
            iotSourceFile.setFileName(fileName);
            final BigDecimal divide = BigDecimal.valueOf(file.getSize()).divide(BigDecimal.valueOf(1048576), 2, RoundingMode.HALF_UP);
            iotSourceFile.setFileSize(divide.doubleValue());
            iotSourceFile.setNewFileName(FileUtils.getName(fileName));
            if (Objects.requireNonNull(file.getOriginalFilename()).endsWith("png")) {
                iotSourceFile.setFileType(AppCmdConstants.SCREEN_SHOT);
            }
            if (Objects.requireNonNull(file.getOriginalFilename()).endsWith("txt")) {
                iotSourceFile.setFileType(AppCmdConstants.LOGFILE);
            }
            iotSourceFile.setDownLoadUrl(url);
            iotSourceFile.setStatus(AppCmdConstants.UN_PUBLISH);
            iotSourceFileService.insertIotSourceFile(iotSourceFile);
            return AjaxResult.success();
        } catch (Exception e) {
            return AjaxResult.error(e.getMessage());
        }
    }
}
